package com.liuqi.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.liuqi.common.Result;
import com.liuqi.entity.Files;
import com.liuqi.entity.User;
import com.liuqi.mapper.FileMapper;
import com.liuqi.utils.TokenUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

/**
 * 专门处理文件上传的相关接口
 */
@RestController
@Transactional
@RequestMapping("/file")
public class FileController {
    @Value("${files.upload.path}")
    private String fileUploadPath;//从配置文件中获取路径
    @Resource
    private FileMapper fileMapper;

    /**
     * 文件上传 接口
     *
     * @param file 前端传过来的文件
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    public String upload(@RequestParam MultipartFile file) throws IOException {//
        String originalFilename = file.getOriginalFilename();//用原始的文件名可能有特殊字符，还有可能重名,所以要对文件进行处理
        String type = FileUtil.extName(originalFilename);
        long size = file.getSize();

        //1.先存储到磁盘

        //定义文件的唯一表示码
        String uuid = IdUtil.fastSimpleUUID();
        String fileUUID = uuid + StrUtil.DOT + type;//文件名（带后缀）
        //判断配置的“文件目录”是否存在，如果不存在就创建一个新的文件目录
        File uploadFile = new File(fileUploadPath + fileUUID);
        if (!uploadFile.getParentFile().exists()) {
            uploadFile.getParentFile().mkdirs();//地址的父文件目录不存在是就创建一个
        }
        String url;
        //把获取到的“文件”存储到磁盘“文件目录”去
        file.transferTo(uploadFile);
        //获取文件的md5,通过对比md5避免重复上传相同内容的文件到磁盘
        String md5 = SecureUtil.md5(uploadFile);//（获取文件的md5时,没有判断该文件是否存在）
        /*//查询文件的md5是否存在
            QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("md5", md5);
            Files files = fileMapper.selectOne(queryWrapper);*/  //==>多次用到（上传和下载），抽取封装为一个方法
        //从数据库查询是否存在记录
        Files dbFiles = getFileByMd5(md5);
        //获取文件的url
        if (dbFiles != null) {//在数据库中能够查到文件
            url = dbFiles.getUrl();
            //由于文件已存在，所以删除刚才已上传的重复文件
            uploadFile.delete();
        } else {//在数据库中查不到文件
            //数据库若不存在重复文件，则不删除刚才上传的文件
            url = "http://localhost:8085/file/" + fileUUID;
        }
        // 2.再存储到数据库
        Files saveFile = new Files();
        saveFile.setName(originalFilename);
        saveFile.setType(type);
        saveFile.setSize(size / 1024);//b->kb
        saveFile.setUrl(url);
        saveFile.setMd5(md5);
        fileMapper.insert(saveFile);
        //System.out.println(md5);
        return url;
    }

    /**
     * 文件下载接口 "http://localhost:8084/file/{fileUUID}"
     *
     * @param fileUUID
     * @param response
     * @throws IOException
     */
    @GetMapping("/{fileUUID}")//fileUUID:就是文件名（带后缀）
    public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException {
        //根据文件的唯一标识码获取文件
        File uploadFile = new File(fileUploadPath + fileUUID);
        //设置输出流的格式
        ServletOutputStream os = response.getOutputStream();
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUUID, "UTF-8"));
        response.setContentType("application/octet-stream");
        //读取上传字节流
        os.write(FileUtil.readBytes(uploadFile));
        os.flush();
        os.close();
    }

    /**
     * 通过MD5查询文件
     *
     * @param md5
     * @return
     */
    private Files getFileByMd5(String md5) {
        //查询文件的md5是否存在
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("md5", md5);
        List<Files> filesList = fileMapper.selectList(queryWrapper);
        return filesList.size() == 0 ? null : filesList.get(0);//存在多条记录只返回第一条记录，三目表达式防止报错
    }

    //更新
    @PostMapping("/update")
    public Result update(@RequestBody Files files) {//@RequestBody:将前台数据隐射为对象
        return Result.success(fileMapper.updateById(files));
    }


    //根据id删除
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {//@PathVariable：表示接受url上的参数
        /*return userMapper.deleteById(id);*/
        Files file = fileMapper.selectById(id);//根据id查询单个文件
        file.setIsDelete(true);//设置逻辑删除字段为true
        fileMapper.updateById(file);
        return Result.success();
    }

    //批量删除
    @PostMapping("/del/batch")
    public Result deleteBatch(@RequestBody List<Integer> ids) {//@PathVariable：表示接受url上的参数
        //select * from sys_file where id in(ids)
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", ids);
        List<Files> files = fileMapper.selectList(queryWrapper);
        for (Files file : files) {
            file.setIsDelete(true);
            fileMapper.updateById(file);
        }
        return Result.success();
    }


    /**
     * 文件分页查询接口
     *
     * @param pageNum
     * @param pageSize
     * @param name
     * @return
     */
    //分页查询: mybatis-plus的方式
    @GetMapping("/page")//接口路径：/user/page
    public Result findPage(@RequestParam Integer pageNum,
                           @RequestParam Integer pageSize,
                           @RequestParam(defaultValue = "") String name) {//@RequestParam:接受?pageNum=1&pgeSize=10
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_deleted", false);
        //queryWrapper.orderByDesc("id");//逆序
        if (!"".equals(name)) {
            queryWrapper.like("name", name);
        }
        //获取当前用户信息
        User currentUser = TokenUtils.getCurrentUser();
        //System.out.println("用户昵称" + currentUser.getNickname());
        //queryWrapper.orderByDesc("id");
        /*queryWrapper.and(w->w.like("nickname",nickname));*/
        return Result.success(fileMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper));
    }
}
